﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Xml.Linq;
using AzukiMap.Element;
using AzukiMap.MapSource;
using AzukiMap.Renderer;
using AzukiMap.Request;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries;
using System.Windows.Controls;
using Label=AzukiMap.Element.Label;

namespace AzukiMap.Layer
{
    public delegate int PostGisGetThemeIdHandler(object sender, PostGisRecord record);

    public class PostGisLayer : VectorLayer
    {
        public event PostGisGetThemeIdHandler GetThemeId;
        protected virtual int OnGetThemeId(object sender, PostGisRecord record)
        {
            if (GetThemeId != null)
            {
                return GetThemeId(this, record);
            }
            return record.ThemeId;
        }

        private PostGisVectorParser _pgParser;
        private PostGisVectorRequest _pgRequest;

        public PostGisLayer(PostGisSource pgSource, string name, IPolygon extent)
            : base(pgSource, name, extent)
        {
            SetRequest(pgSource);
        }

        public PostGisLayer(PostGisSource pgSource, string name)
            : base(pgSource, name)
        {
            SetRequest(pgSource);
        }

        public PostGisLayer()
        {
        }

        public PostGisSource PgSource
        {
            get { return (PostGisSource) base.MapSource; }
            set
            {
                if ( value == null)
                    throw new ArgumentNullException();

                base.MapSource = value;
                SetRequest(PgSource);
            }
        }

        private void SetRequest(PostGisSource pgSource)
        {
            if (pgSource.GetColumnDataUri != null)
            {
                _pgRequest = new PostGisVectorRequest(this, pgSource.GetColumnDataUri);
            }
            else
            {
                _pgRequest = new PostGisVectorRequest(this);
            }
            _pgRequest.GetDataCompleted += PgRequestGetDataCompleted;
        }

        public override void Draw()
        {
            if (!CheckDrawingStatus())
            {
                return;
            }
            base.Draw();
            IsRendering = true;
            _pgRequest.Request();
        }

        public override void Redraw()
        {
            base.Redraw();
            if (!CheckDrawingStatus())
            {
                return;
            }

            IsRendering = true;
            _pgRequest.Request();
        }

        private bool CheckDrawingStatus()
        {
            if (IsRendering)
            {
                return false;
            }
            if (!IsVisible)
            {
                return false;
            }
            if (!CheckScale())
            {
                return false;
            }
            if (!IsDrawable)
            {
                return false;
            } 
            return true;
        }

        private int GetRecordThemeId(PostGisRecord record)
        {
            return OnGetThemeId(this, record);
        }

        private void PgRequestGetDataCompleted(object sender, GetDataCompletedArgs e)
        {
#if !SILVERLIGHT
            e.DataStream.BaseStream.ReadTimeout = 10000000;
#endif
            _pgParser = new PostGisVectorParser(e.DataStream);
            int numOfGeom = _pgParser.NumOfObjects;

            IVectorStyle vStyle;
            _renderer.StartRendering();
            foreach (PostGisRecord record in _pgParser)
            {
                if (_rendered.ContainsKey(record.Gid))
                {
                    continue;
                }

                int themeId = GetRecordThemeId(record);

                if (themeId == -1)
                {
                    vStyle = DefaultStyle;
                }
                else
                {
                    vStyle = LayerThemes[themeId].Style;
                }

                if (DrawsAsProportionalSymbol &&  record.Attributes != null)
                {
                    double size = 0;
                    if (record.Attributes.Length > 0)
                        if (!double.TryParse(record.Attributes[0], out size))
                            size = 0;

                    List<FrameworkElement> elems = _renderer.DrawGeometry(record.Gid, record.Geometry, vStyle, size * ProportionalSymbolFactor);
                    SetEventsOnElement(elems);
                }
                else
                {
                    List<FrameworkElement> elems = _renderer.DrawGeometry(record.Gid, record.Geometry, vStyle);
                    SetEventsOnElement(elems);
                }

                if (record.Attributes != null)
                {
                    var label = new Label
                                    {
                                        Id = record.Gid,
                                        Geom = record.Geometry,
                                        Text = record.Attributes[0],
                                        HorizontalAlignment = LabelHorizontalAlignment,
                                        VerticalAlignment = LabelVerticalAlignment,
                                        Margin = LabelMargin,
                                        NeedsBackground = LabelNeedsBackground,
                                        FontWeight = LabelFontWeight,
                                        BackgroundFontWeight = LabelBackgroundFontWeight,
                                        BackgroundOffsetX = LabelBackgroundOffsetX,
                                        BackgroundOffsetY = LabelBackgroundOffsetY
                                    };
                    if (LabelBrush != null)
                        label.Foreground = LabelBrush;
                    if (LabelFont != null)
                        label.Font = LabelFont;
                    if (LabelSize != 0)
                        label.FontSize = LabelSize;
                    if (LabelBackground != null)
                        label.Background = LabelBackground;
                   
                    TextBlock labelElement = LabelLayer.Add(label);
                    if ( labelElement != null )
                    {
                        
                    }
                }

                _rendered.Add(record.Gid, true);

            }
#if !SILVERLIGHT
                if (UsesDrawingVisual || UsesRenderTargetBitmap)
                {
                    _pgParser = null;
                }
#endif
            _renderer.FinishRendering();
            IsRendering = false;
        }

        public override XElement ToXml()
        {
            return ToXml("PostGisLayer");
        }

        public override XElement ToXml(string elementName)
        {
            XElement vectorLayerXml = base.ToXml(elementName);
            return vectorLayerXml;
        }

        public override void Parse(XElement layerXml)
        {
            base.Parse(layerXml);
            var source = new PostGisSource();
            source.Parse(layerXml.Element("PostGisSource"));
            PgSource = source;
            VectorSource = source;
            MapSource = source;
            VectorType = source.VectorType;
            SetRequest(PgSource);
        }
    }
}